{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "92c512aa",
   "metadata": {},
   "source": [
    "# Analyzing and tuning a transmon qubit with a resonator\n",
    "We will showcase two methods (EPR amd LOM) to analyze the same design. Specifically, we will use here the `advanced` methods to run the simulations and analysis, which directly contorl renderers and external packages. Please refer to the tutorial notebooks 4.1 and 4.2 to follow the `suggested` flow to run the analysis."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88653173",
   "metadata": {},
   "source": [
    "## Index\n",
    "#### Transmon & resonator design\n",
    "1. Prepare the single transmon qubit layout in qiskit-metal. <br>\n",
    "\n",
    "#### Transmon & resonator analysis using EPR method\n",
    "1. Set-up and run a finite element simulate to extract the eigenmode. <br>\n",
    "1. Display EM fields to inspect quality of the setup. <br>\n",
    "1. Identify junction parameters for the EPR analysis. <br>\n",
    "1. Run EPR analysis on single eigenmode. <br>\n",
    "1. Get qubit freq and anharmonicity. <br>\n",
    "1. Calculate EPR of substrate.  <br>\n",
    "\n",
    "#### Transmon & resonator analysis using LOM method\n",
    "1. Calculate the capacitance matrix. <br>\n",
    "1. Execute analysis on extracted LOM. <br>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7c42360e",
   "metadata": {},
   "source": [
    "## Prerequisite\n",
    "You need to have a working local installation of Ansys.<br>\n",
    "Also you will need the following directives and inports."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e5942903",
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "\n",
    "import qiskit_metal as metal\n",
    "from qiskit_metal import designs, draw\n",
    "from qiskit_metal import MetalGUI, Dict, Headings\n",
    "import pyEPR as epr"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "740b82be",
   "metadata": {},
   "source": [
    "# 1. Create the Qbit design\n",
    "\n",
    "Fix the design dimensions that you intend to reflect in the design rendering. <br>\n",
    "Note that the design size extends from the origin into the first quadrant."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a90b9c4b",
   "metadata": {},
   "outputs": [],
   "source": [
    "design = designs.DesignPlanar({}, True)\n",
    "design.chips.main.size['size_x'] = '2mm'\n",
    "design.chips.main.size['size_y'] = '2mm'\n",
    "\n",
    "gui = MetalGUI(design)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46a0fb9a",
   "metadata": {},
   "source": [
    "Create a single transmon with one readout resonator. Please refer to the notebook tutorials 4.11 ad 4.12 if you're not familiar with the code in the cell below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6b0379d5",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket\n",
    "from qiskit_metal.qlibrary.terminations.open_to_ground import OpenToGround\n",
    "from qiskit_metal.qlibrary.tlines.meandered import RouteMeander\n",
    "\n",
    "design.delete_all_components()\n",
    "\n",
    "q1 = TransmonPocket(design, 'Q1', options = dict(\n",
    "    pad_width = '425 um', \n",
    "    pocket_height = '650um',\n",
    "    connection_pads=dict(\n",
    "        readout = dict(loc_W=+1,loc_H=+1, pad_width='200um')\n",
    "    )))\n",
    "otg = OpenToGround(design, 'open_to_ground', options=dict(pos_x='1.75mm',  pos_y='0um', orientation='0'))\n",
    "readout = RouteMeander(design, 'readout',  Dict(\n",
    "            total_length='6 mm',\n",
    "            hfss_wire_bonds = True,\n",
    "            fillet='90 um',\n",
    "            lead = dict(start_straight='100um'),\n",
    "            pin_inputs=Dict(\n",
    "                start_pin=Dict(component='Q1', pin='readout'),\n",
    "                end_pin=Dict(component='open_to_ground', pin='open')), ))\n",
    "\n",
    "gui.rebuild()\n",
    "gui.autoscale()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2fb5180b",
   "metadata": {},
   "source": [
    "# 2. Analyze the transmon & resonator using the Eigenmode-EPR method\n",
    "\n",
    "In this section we will use a semi-manual (advanced) analysis flow. Please refer to tutorial 4.2 for the `suggested` method. As illustrated, the methods are equivalent, but the advanced method allows you to directly override some renderer-specific settings.\n",
    "\n",
    "### Finite Element Eigenmode Analysis\n",
    "\n",
    "#### Setup\n",
    "\n",
    "Select the analysis you intend to run from the `qiskit_metal.analyses` collection.<br>\n",
    "Select the design to analyze and the tool to use for any external simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5cd88ae5",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit_metal.analyses.quantization import EPRanalysis\n",
    "eig_qres = EPRanalysis(design, \"hfss\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d012fa9d",
   "metadata": {},
   "source": [
    "For the Eigenmode simulation portion, you can either:\n",
    "1. Use the `eig_qres` user-friendly methods (see tutorial 4.2)\n",
    "2. Control directly the simulation tool from the tool's GUI (outside metal - see specific vendor instructions)\n",
    "3. Use the renderer methods\n",
    "In this section we show the advanced method (method 3).\n",
    "\n",
    "The renderer can be reached from the analysis class. Let's give it a shorter alias."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "64a55233",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss = eig_qres.sim.renderer"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "106294fa",
   "metadata": {},
   "source": [
    "Now we connect to the tool using the unified command."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2cc84605",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "622a1393",
   "metadata": {},
   "source": [
    "The previous command is supposed to open ansys (if closed), create a new project and finally connect this notebook to it.\n",
    "\n",
    "If for any reason the previous cell failed, please try the manual path described in the next three cells:\n",
    "1. uncomment and execute only **one** of the lines in the first cell.\n",
    "1. uncomment and execute the second cell.\n",
    "1. uncomment and execute only **one** of the lines in the third cell."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c1d93d7d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# hfss.open_ansys()   # this opens Ansys 2021 R2 if present\n",
    "# hfss.open_ansys(path_var='ANSYSEM_ROOT211')\n",
    "# hfss.open_ansys(path='C:\\Program Files\\AnsysEM\\AnsysEM21.1\\Win64')\n",
    "# hfss.open_ansys(path='../../../Program Files/AnsysEM/AnsysEM21.1/Win64')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "19f18cdf",
   "metadata": {},
   "outputs": [],
   "source": [
    "# hfss.new_ansys_project()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7fcd6a7d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# hfss.connect_ansys()\n",
    "# hfss.connect_ansys('C:\\\\project_path\\\\', 'Project1')  # will open a saved project before linking the Jupyter session"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e0fbfafb",
   "metadata": {},
   "source": [
    "#### Execute simulation and verify convergence\n",
    "\n",
    "Create and activate an eigenmode design called \"TransmonReadout\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f48fad4a",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.activate_ansys_design(\"TransmonReadout\", 'eigenmode')  # use new_ansys_design() to force creation of a blank design"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46ef1272",
   "metadata": {},
   "source": [
    "Render everything inlcuding the qubit and resonator in Metal, to \"TransmonReadout\" design in Ansys."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ee77b3c1",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.render_design(['Q1', 'readout', 'open_to_ground'], [])\n",
    "hfss.save_screenshot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e587d3c",
   "metadata": {},
   "source": [
    "Set the convergence parameters and junction properties in the Ansys design. <br>\n",
    "Then run the analysis and plot the convergence.\n",
    "\n",
    "Note that we seek 2 eigenmodes - one with stronger fields near the transmon, the other with stronger fields near the resonator."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "19d3966b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Analysis properties\n",
    "setup = hfss.pinfo.setup\n",
    "setup.n_modes = 2\n",
    "setup.passes = 10\n",
    "print(f\"\"\"\n",
    "Number of eigenmodes to find             = {setup.n_modes}\n",
    "Number of simulation passes              = {setup.passes}\n",
    "Convergence freq max delta percent diff  = {setup.delta_f}\n",
    "\"\"\")\n",
    "\n",
    "pinfo = hfss.pinfo\n",
    "pinfo.design.set_variable('Lj', '10 nH')\n",
    "pinfo.design.set_variable('Cj', '0 fF')\n",
    "\n",
    "setup.analyze()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41c6740a",
   "metadata": {},
   "source": [
    "To plot the results you can use the `plot_convergences()` method from the `eig_qres.sim` object. The method will read the data from the variables local to the `eig_qres.sim` object, so we first need to assign the simulation results to these two variables. let's do both (assignment and plotting) in the next cell."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0ccdedbf",
   "metadata": {},
   "outputs": [],
   "source": [
    "eig_qres.sim.convergence_t, eig_qres.sim.convergence_f, _ = hfss.get_convergences()\n",
    "eig_qres.sim.plot_convergences()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0856cba",
   "metadata": {},
   "source": [
    "#### Plot the EM field for inspection\n",
    "Display the Ansys modeler window and plot the E-field on the chip's surface."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "05bf173e",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.modeler._modeler.ShowWindow()\n",
    "hfss.plot_fields('main')\n",
    "hfss.save_screenshot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b9c762a",
   "metadata": {},
   "source": [
    "Delete the newly created E-field plot before moving on."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "16797ae7",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.clear_fields(['Mag_E1'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48279c3b",
   "metadata": {},
   "source": [
    "To look at the second eigenmode created, we use the following command, and then plot the corresponding E-field."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bde5c793",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.set_mode(2, \"Setup\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "93d03301",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.modeler._modeler.ShowWindow()\n",
    "hfss.plot_fields('main')\n",
    "hfss.save_screenshot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c31d0f4",
   "metadata": {},
   "source": [
    "We delete this design to prepare for further analysis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ee564a3c",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.clear_fields(['Mag_E1'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c86d2f8e",
   "metadata": {},
   "source": [
    "### EPR Analysis\n",
    "In the `suggested` (tutorial 4.2) flow, we would now prepare the setup using `eig_qres.setup` and run the analysis with `eig_qres.run_epr()`. Notice that this method requires previous set of the `eig_qres` variables `convergence_t` and `convergence_f` like we did a thee cells earlier.\n",
    "\n",
    "However we here exemplify the advanced approach, which is Ansys-specific since it uses the pyEPR module methods directly.\n",
    "#### Setup\n",
    "Identify the non-linear (Josephson) junctions in the model. You will need to list the junctions in the epr setup.\n",
    "\n",
    "In this case there's only one junction, namely 'jj'. Let's see what we need to change in the default setup."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fd896514",
   "metadata": {},
   "outputs": [],
   "source": [
    "pinfo = hfss.pinfo\n",
    "pinfo.junctions['jj'] = {'Lj_variable': 'Lj', 'rect': 'JJ_rect_Lj_Q1_rect_jj', \n",
    "                             'line': 'JJ_Lj_Q1_rect_jj_',  'Cj_variable': 'Cj'}\n",
    "pinfo.validate_junction_info() # Check that valid names of variables and objects have been supplied\n",
    "pinfo.dissipative['dielectrics_bulk'] = ['main'] # Dissipative elements: specify"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38af844a",
   "metadata": {},
   "source": [
    "#### Execute the energy distribution analysis\n",
    "\n",
    "Execute microwave analysis on eigenmode solutions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7311d0c0",
   "metadata": {},
   "outputs": [],
   "source": [
    "eprd = epr.DistributedAnalysis(pinfo)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8527483",
   "metadata": {},
   "source": [
    "Find the electric and magnetic energy stored in the substrate and the system as a whole."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8192b17a",
   "metadata": {},
   "outputs": [],
   "source": [
    "ℰ_elec = eprd.calc_energy_electric()\n",
    "ℰ_elec_substrate = eprd.calc_energy_electric(None, 'main')\n",
    "ℰ_mag = eprd.calc_energy_magnetic()\n",
    "\n",
    "print(f\"\"\"\n",
    "ℰ_elec_all       = {ℰ_elec}\n",
    "ℰ_elec_substrate = {ℰ_elec_substrate}\n",
    "EPR of substrate = {ℰ_elec_substrate / ℰ_elec * 100 :.1f}%\n",
    "\n",
    "ℰ_mag_all       = {ℰ_mag}\n",
    "ℰ_mag % of ℰ_elec_all  = {ℰ_mag / ℰ_elec * 100 :.1f}%\n",
    "\"\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a50f4f5",
   "metadata": {},
   "source": [
    "#### Run EPR analysis\n",
    "\n",
    "Perform EPR analysis for all modes and variations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "be7572f0",
   "metadata": {},
   "outputs": [],
   "source": [
    "eprd.do_EPR_analysis()\n",
    "\n",
    "# 4a. Perform Hamiltonian spectrum post-analysis, building on mw solutions using EPR\n",
    "epra = epr.QuantumAnalysis(eprd.data_filename)\n",
    "epra.analyze_all_variations(cos_trunc = 8, fock_trunc = 7)\n",
    "\n",
    "# 4b. Report solved results\n",
    "swp_variable = 'Lj' # suppose we swept an optimetric analysis vs. inductance Lj_alice\n",
    "epra.plot_hamiltonian_results(swp_variable=swp_variable)\n",
    "epra.report_results(swp_variable=swp_variable, numeric=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d3d62dac",
   "metadata": {},
   "source": [
    "Release Ansys session"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "451e36a6",
   "metadata": {},
   "outputs": [],
   "source": [
    "eig_qres.sim.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a66f63f9",
   "metadata": {},
   "source": [
    "# 3. Analyze the transmon using the LOM method\n",
    "\n",
    "In this section we will use a semi-manual (advanced) analysis flow. Please refer to tutorial 4.1 for the `suggested` method. As illustrated, the methods are equivalent, but the advanced method allows you to directly override some renderer-specific settings.\n",
    "\n",
    "### Capacitance matrix extraction\n",
    "#### Setup\n",
    "Select the analysis you intend to run from the `qiskit_metal.analyses` collection.<br>\n",
    "Select the design to analyze and the tool to use for any external simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "012aa249",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit_metal.analyses.quantization import LOManalysis\n",
    "c2 = LOManalysis(design, \"q3d\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad54efa6",
   "metadata": {},
   "source": [
    "For the capacitive simulation portion, you can either:\n",
    "1. Use the `c2` user-friendly methods (see tutorial 4.1)\n",
    "2. Control directly the simulation tool from the tool's GUI (outside metal - see specific vendor instructions)\n",
    "3. Use the renderer methods\n",
    "In this section we show the advanced method (method 3).\n",
    "\n",
    "The renderer can be reached from the analysis class. Let's give it a shorter alias."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11460c6d",
   "metadata": {},
   "outputs": [],
   "source": [
    "q3d = c2.sim.renderer"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "97c655c0",
   "metadata": {},
   "source": [
    "Now we connect to the simulation tool, similarly to what we have done for the eigenmode analysis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bdedfbdf",
   "metadata": {},
   "outputs": [],
   "source": [
    "q3d.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91df0625",
   "metadata": {},
   "source": [
    "If the simulator is already open, the line above will simply connect to the open session, project and design.\n",
    "\n",
    "#### Execute simulation and verify convergence\n",
    "\n",
    "Create and activate a q3d design called \"TransmonResonator_q3d\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "001ea56c",
   "metadata": {},
   "outputs": [],
   "source": [
    "q3d.activate_ansys_design(\"TransmonResonator_q3d\", 'capacitive')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "315dbeb0",
   "metadata": {},
   "source": [
    "Next, we render the exisitng design to Ansys Q3D for analysis. To ensure that the readout is insulated from the ground plane, we set the 'readout' pin of Q1 to have an open termination."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2dff0125",
   "metadata": {},
   "outputs": [],
   "source": [
    "q3d.render_design(['Q1'], [('Q1','readout')])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c426b657",
   "metadata": {},
   "source": [
    "Execute the capacitance extraction and verify converengence. This cell analyzes the default setup."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "01ffdd05",
   "metadata": {},
   "outputs": [],
   "source": [
    "q3d.analyze_setup(\"Setup\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d69b12de",
   "metadata": {},
   "source": [
    "This simulation had 4 nets, the two charge islands of the floating transmon, the readout coupler, and the ground, resulting in a 4x4 capacitance matrix. Output is of type DataFrame."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4dd86c34",
   "metadata": {},
   "outputs": [],
   "source": [
    "c2.sim.capacitance_matrix, c2.sim.units = q3d.get_capacitance_matrix()\n",
    "c2.sim.capacitance_all_passes, _ = q3d.get_capacitance_all_passes()\n",
    "c2.sim.capacitance_matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b963f4ab",
   "metadata": {},
   "source": [
    "### LOM Analysis\n",
    "Now we provide the junction lumped element values, and complete the analysis by plotting the convergence. This is the same steps used in the `suggested` flow from tutorial 4.1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9bac0dda",
   "metadata": {},
   "outputs": [],
   "source": [
    "c2.setup.junctions=Dict(Lj=12.31, Cj=2)\n",
    "c2.setup.freq_readout = 7.0\n",
    "c2.setup.freq_bus = []\n",
    "\n",
    "c2.run_lom()\n",
    "c2.lumped_oscillator_all"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8b451457",
   "metadata": {},
   "source": [
    "And plot the convergence."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "58aa13fb",
   "metadata": {},
   "outputs": [],
   "source": [
    "c2.plot_convergence();\n",
    "c2.plot_convergence_chi()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "81c8fb72",
   "metadata": {},
   "source": [
    "Release the simulator and close the analysis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4ea30642",
   "metadata": {},
   "outputs": [],
   "source": [
    "c2.sim.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2cf14a4f",
   "metadata": {},
   "source": [
    "(optional) close the GUI."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "95b41712",
   "metadata": {},
   "outputs": [],
   "source": [
    "# gui.main_window.close()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
